#include "deck.h"


#include <algorithm>
#include <assert.h>

Card::Card(Rank r, Suit s):
	rank(r),
	suit(s)
{
	if (rank == Card::JokerA || rank == Card::JokerB)
	{
		suit = Card::Clubs;
	}
}

bool Card::operator==(const Card& rhs)
{
	if ((GetRank() == rhs.GetRank()) && (GetSuit() == rhs.GetSuit()))
	{
		return true;
	}

	return false;
}

Card::Rank Card::GetRank() const
{
	return rank;
}

Card::Suit Card::GetSuit() const
{
	return suit;
}

int Card::Value() const
{
	int value;
	switch (rank)
	{
		case Card::JokerA:
		case Card::JokerB:
			value = 53;
			break;
		default:
			value = rank + 13 * suit;
	}

	return value;
}

Deck::Deck()
{
	cards.push_back(Card(Card::Ace, Card::Clubs));
	cards.push_back(Card(Card::Two, Card::Clubs));
	cards.push_back(Card(Card::Three, Card::Clubs));
	cards.push_back(Card(Card::Four, Card::Clubs));
	cards.push_back(Card(Card::Five, Card::Clubs));
	cards.push_back(Card(Card::Six, Card::Clubs));
	cards.push_back(Card(Card::Seven, Card::Clubs));
	cards.push_back(Card(Card::Eight, Card::Clubs));
	cards.push_back(Card(Card::Nine, Card::Clubs));
	cards.push_back(Card(Card::Ten, Card::Clubs));
	cards.push_back(Card(Card::Jack, Card::Clubs));
	cards.push_back(Card(Card::Queen, Card::Clubs));
	cards.push_back(Card(Card::King, Card::Clubs));

	cards.push_back(Card(Card::Ace, Card::Diamonds));
	cards.push_back(Card(Card::Two, Card::Diamonds));
	cards.push_back(Card(Card::Three, Card::Diamonds));
	cards.push_back(Card(Card::Four, Card::Diamonds));
	cards.push_back(Card(Card::Five, Card::Diamonds));
	cards.push_back(Card(Card::Six, Card::Diamonds));
	cards.push_back(Card(Card::Seven, Card::Diamonds));
	cards.push_back(Card(Card::Eight, Card::Diamonds));
	cards.push_back(Card(Card::Nine, Card::Diamonds));
	cards.push_back(Card(Card::Ten, Card::Diamonds));
	cards.push_back(Card(Card::Jack, Card::Diamonds));
	cards.push_back(Card(Card::Queen, Card::Diamonds));
	cards.push_back(Card(Card::King, Card::Diamonds));
	
	cards.push_back(Card(Card::Ace, Card::Hearts));
	cards.push_back(Card(Card::Two, Card::Hearts));
	cards.push_back(Card(Card::Three, Card::Hearts));
	cards.push_back(Card(Card::Four, Card::Hearts));
	cards.push_back(Card(Card::Five, Card::Hearts));
	cards.push_back(Card(Card::Six, Card::Hearts));
	cards.push_back(Card(Card::Seven, Card::Hearts));
	cards.push_back(Card(Card::Eight, Card::Hearts));
	cards.push_back(Card(Card::Nine, Card::Hearts));
	cards.push_back(Card(Card::Ten, Card::Hearts));
	cards.push_back(Card(Card::Jack, Card::Hearts));
	cards.push_back(Card(Card::Queen, Card::Hearts));
	cards.push_back(Card(Card::King, Card::Hearts));
	
	cards.push_back(Card(Card::Ace, Card::Spades));
	cards.push_back(Card(Card::Two, Card::Spades));
	cards.push_back(Card(Card::Three, Card::Spades));
	cards.push_back(Card(Card::Four, Card::Spades));
	cards.push_back(Card(Card::Five, Card::Spades));
	cards.push_back(Card(Card::Six, Card::Spades));
	cards.push_back(Card(Card::Seven, Card::Spades));
	cards.push_back(Card(Card::Eight, Card::Spades));
	cards.push_back(Card(Card::Nine, Card::Spades));
	cards.push_back(Card(Card::Ten, Card::Spades));
	cards.push_back(Card(Card::Jack, Card::Spades));
	cards.push_back(Card(Card::Queen, Card::Spades));
	cards.push_back(Card(Card::King, Card::Spades));

	cards.push_back(Card(Card::JokerA, Card::Clubs));
	cards.push_back(Card(Card::JokerB, Card::Clubs));
}

void Deck::Move(Card card, int amount)
{
	assert (amount > 0);

	std::list<Card>::iterator iter = std::find(cards.begin(), cards.end(), card);
	iter = cards.erase(iter);
	for (int i = 0; i < amount; ++i) 
	{ 
		if (iter == cards.end())
		{
			iter = cards.begin();
		}	
		++iter; 
	}
	cards.insert(iter, card);
}


std::list<int> Deck::GetValues() const
{
	std::list<int> values;
	std::list<Card>::const_iterator cardIter;
	for (cardIter = cards.begin(); cardIter != cards.end(); ++cardIter)
	{
		values.push_back((*cardIter).Value());
	}
	return values;
}

void Deck::Triple_Cut()
{
	std::list<Card>::iterator bottom_position;
	std::list<Card> bottom_cut;
	std::list<Card>::iterator top_position;
	std::list<Card> top_cut;

	std::list<Card>::iterator iter_jokerA = std::find(cards.begin(), cards.end(), Card(Card::JokerA, Card::Clubs));
	std::list<Card>::iterator iter_jokerB = std::find(cards.begin(), cards.end(), Card(Card::JokerB, Card::Clubs));

	bool joker_a_below_joker_b = distance(cards.begin(), iter_jokerA) > distance(cards.begin(), iter_jokerB);

	bottom_position = joker_a_below_joker_b ? iter_jokerA : iter_jokerB;
	top_position = joker_a_below_joker_b ? iter_jokerB : iter_jokerA;

	bottom_cut.splice(bottom_cut.begin(), cards, ++bottom_position, cards.end()); 
	top_cut.splice(top_cut.begin(), cards, cards.begin(), top_position); 

	cards.splice(cards.begin(), bottom_cut);
	cards.splice(cards.end(), top_cut);
}

void Deck::Count_Cut()
{
	std::list<Card> count_cut;

	std::list<Card>::iterator bottom_card = cards.end();
	--bottom_card;

	std::list<Card>::iterator cut_card = cards.begin();
	advance( cut_card, (*bottom_card).Value());

	count_cut.splice(count_cut.begin(), cards, cards.begin(), cut_card); 

	cards.splice(bottom_card, count_cut);
}
	
char Deck::Output_Letter()
{
	std::list<Card>::iterator top_card = cards.begin();
	advance(top_card, (*top_card).Value());
	int value = (*top_card).Value();

	if (value > 26)
	{
		value -= 26;
	}

	if (value > 26)
	{
		return 0;
	}

	char letter = value + 64;
	return letter;
}

void Deck::Shuffle()
{
	std::vector<Card> cards_as_vector;
	cards_as_vector.resize(54, Card(Card::Ace, Card::Clubs));

	std::copy( cards.begin(), cards.end(), cards_as_vector.begin() );

	std::random_shuffle( cards_as_vector.begin(), cards_as_vector.end() );

	std::copy( cards_as_vector.begin(), cards_as_vector.end(), cards.begin() );
}
